#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv) {
	if (argc != 3) {
		fprintf(stderr, "usage: x86_64-analyze-paging-struct <struct type> <entry>\n");
		fprintf(stderr, "where struct type is one of: pml5e pml4e pdpte pde pte big-pdpte big-pde\n");
		return 1;
	}
	uint64_t e = strtoull(argv[2], NULL, 0);
#define o(i, t, f) if (e & (1ULL << i)) puts(t); else puts(f);
	o(0, "present", "non-present");
	o(1, "writable", "non-writable");
	o(2, "user and kernel mapping", "kernel mapping");
	o(3, "pwt 1", "pwt 0");
	o(4, "pcd 1", "pcd 0");
	o(5, "has been read", "has not been read");
	bool is_big = !strcmp(argv[1], "big-pdpte")
		|| !strcmp(argv[1], "big-pde")
		|| !strcmp(argv[1], "pte");
	if (is_big) {
		o(6, "has been written to", "has not been written to");
	} else {
		o(6, "avl6 1", "avl6 0");
	}
	if (!strcmp(argv[1], "pte")) {
		o(7, "pat 1", "pat 0");
	} else {
		if (!strcmp(argv[1], "pml4e") || !strcmp(argv[1], "pml5e")) {
			o(7, "RESERVED7 SET", "reserved7 clear");
		} else {
			o(7, "big page", "4k page");
		}
	}
	if (is_big) {
		o(7, "global", "not global");
	} else {
		printf("avl8 %i\n", (e >> 8) & 15);
	}
	printf("addr %016lx\n", e & 0x000ffffffffff000);
	if (is_big) {
		printf("avl52 %i\n", (e >> 52) & 127);
		printf("pkru %i\n", (e >> 59) & 15);
	} else {
		printf("avl52 %i\n", (e >> 52) & 2047);
	}
	o(63, "non-executable", "executable");
}
